package NWPackage;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import javax.swing.text.html.HTMLDocument.Iterator;

import NW_MC.AgentsMinMaxMatrix;

public class BordaProtocol implements Protocol {
	
	private AgentsMinMaxMatrix agentsMinMax;
	//List<String> optionalWinners;
	private PairPreferdCandidateMatrix allQueriesFound;
	
	//more queries = the new query and all the new transitive closer
	private List<PairPreferdCandidateCell> moreQueriesFound;
	
	public BordaProtocol()
	{
		agentsMinMax = new AgentsMinMaxMatrix();
		moreQueriesFound = new ArrayList<PairPreferdCandidateCell>();
		allQueriesFound = new PairPreferdCandidateMatrix();
	}
	
	public void Initial(String[] optionalWinners)
	{
		//for each agent, create MinMaxMatrix
		agentsMinMax.InitialAgentsMatrix(Arrays.asList(optionalWinners));
		
	}
	
	public void calcMinMax(PairPreferdCandidateCell newQueryFound, List<String> optionalWinners)
	{	
		//check for Transitive Queries:
		//-----debug with no transitive checks-----------------//
		moreQueriesFound = CheckTransitive(newQueryFound);
	
		//update the Past Query_Found List
		allQueriesFound.setAnswers(moreQueriesFound);
		
		//for each Query  - set the Candidates Min and Max Values:
		agentsMinMax.setQueriesMinMax(moreQueriesFound);
		
		//calc sum for min and Max
		agentsMinMax.calcSumMinMax(optionalWinners);
		
	}
	
	public void initial_calcMinMax(List<String> optionalWinners)
	{				
		//update the Past Query_Found List
		allQueriesFound.setAnswers(moreQueriesFound);
		
		//for each Query  - set the Candidates Min and Max Values:
		agentsMinMax.setQueriesMinMax(moreQueriesFound);
		
		//calc sum for min and Max
		agentsMinMax.calcSumMinMax(optionalWinners);
		
	}

	/***
	 * 
	 * @param opionalWinners List
	 * @return update the necessaryList with Candidate who's Min >= all other's Max scores
	 */
	public List<String> UpdateNecessary(List<String> optionalWinners) {
		List<String> necessaryList = new ArrayList<String>();		
		//Necessary is when Min >= all other Maxs:				
		java.util.Iterator<String>  it =   optionalWinners.iterator();
		while (it.hasNext()){
			String cand = it.next();
			int min_cand = agentsMinMax.getMin(cand);
			java.util.Iterator<String>  it2 =   optionalWinners.iterator();
			boolean flag = true;
			while(it2.hasNext()){
				String other_cand = it2.next();
				if (!cand.equals(other_cand)){
				    int max_other = agentsMinMax.getMax(other_cand);
					if(min_cand < max_other)
						flag = false;
				}//if
			}//while2
			if (flag){
				necessaryList.add(cand);
			}
		}//while1
		return necessaryList;
				 
	}
	
	/*Lihi's addition, finds max in NW table*/
	public List<String> findMaxCandidate(List<String> optionalWinners) {
		int max = 0;		
		List<String> maxCands = new ArrayList<String>();
		for (String otherCandidate : optionalWinners) {
			int prevMax = agentsMinMax.getMax(otherCandidate);
		    if (prevMax > max){
			   max = prevMax;			  
			   maxCands.clear();
			   maxCands.add(otherCandidate);
	    	}
		    else if (prevMax == max){
		    	maxCands.add(otherCandidate);
		    }
		}		
		return maxCands;			
	}
	
	/*Lihi's addition, finds the cand the is 2nd*/
	public List<String> find2ndMaxCand(List<String> optionalWinners, String maxCand){
		int max = 0;
		List<String> maxCands = new ArrayList<String>();
		//String secondcand = null;
		for (String otherCandidate : optionalWinners) {
			if (!otherCandidate.equals(maxCand)){  //for each cand but the maxCand
				int prevMax = agentsMinMax.getMax(otherCandidate);
				if (prevMax > max){
					   max = prevMax;			  
					   maxCands.clear();
					   maxCands.add(otherCandidate);
			    	}
				    else if (prevMax == max){
				    	maxCands.add(otherCandidate);
				    }
				}	
		}
				return maxCands;			
			}
	
	/***
	 * 
	 * @param optionalWinners List
	 * @return list with all candidates whos Max >= all other's Min score
	 */
	public List<String> UpdatePossible(List<String> optionalWinners) {
		List<String> newOptionalList = new ArrayList<String>();
		
		//optional is when Max >= all other Mins
		boolean isOptional;
		for (int i = 0; i< optionalWinners.size(); i++) {
			isOptional = true;
			int max = agentsMinMax.getMax(optionalWinners.get(i));
			//check agains all other candidates
			for (String otherCandidate : optionalWinners) {
				if (! otherCandidate.equals(optionalWinners.get(i)))
					if(agentsMinMax.getMin(otherCandidate) > max)
				{
					isOptional = false;
					break;
				}
			}
			if (isOptional)
			{
				newOptionalList.add(optionalWinners.get(i));
			}
		}
		return newOptionalList;
			
			
		
	}
	
	/***
	 * 
	 * @param Cell with the new "Min-Entropy" query
	 * @return List with all the queries added from the Transitive Closure Law.
	 */
	private List<PairPreferdCandidateCell> CheckTransitive(PairPreferdCandidateCell newQueryFound) {
		
		List<PairPreferdCandidateCell> newAgentQueries = new ArrayList<PairPreferdCandidateCell>();
		List<PairPreferdCandidateCell> agentQueries = allQueriesFound.getCellsByAgent(newQueryFound.getAgentName());

		//if this agent already has past queries:
		
		if (agentQueries!=null){	
			newAgentQueries.add(newQueryFound);
			newAgentQueries = TransitiveClosure.getClosure(agentQueries);
		}
		newAgentQueries.add(newQueryFound);
		return newAgentQueries;
	}
	
	
	@SuppressWarnings("unused")
	private PairPreferdCandidateCell TransitiveMerge(
			PairPreferdCandidateCell query1,
			PairPreferdCandidateCell query2) {
		
		if (query1!=null && query2 !=null)
		{
			String[] candidates1 = query1.getCandidatesByPrefferedOrder();
			String[] candidates2 = query2.getCandidatesByPrefferedOrder();
			
			///check if making Transitive rule:
			if (candidates1[0] ==  candidates2[1])
			{
				return new PairPreferdCandidateCell(query1.getAgentName(),candidates1[1],candidates2[0],candidates1[1]);
			}
			if (candidates1[1] == candidates2[0])
			{
				return new PairPreferdCandidateCell(query1.getAgentName(),candidates1[0],candidates2[1],candidates2[1]); 
			}
		}
		
		return null;
	}
	
	public List<PairPreferdCandidateCell> getAllNewQueries(){
		return this.moreQueriesFound;
	}
	
	@SuppressWarnings("unused")
	private List<PairPreferdCandidateCell> DontCheckTransitive(
			PairPreferdCandidateCell newQueryFound) {
		
		List<PairPreferdCandidateCell> newAgentQueries = new ArrayList<PairPreferdCandidateCell>();

		newAgentQueries.add(newQueryFound);
		return newAgentQueries;
		
	
	}
	
	public int get_maxSum_for_cand(String candidate){
		return agentsMinMax.getMax(candidate);
	}
	
	public int get_minSum_for_cand(String candidate){
		return agentsMinMax.getMin(candidate);
	}
}
